#include <QDBusConnection>
#include <QDBusConnectionInterface>
#include <QDBusReply>
#include <QDebug>
#include "X11Picker.h"
#include "DeepinMonitor.h"
#include "common.h"
#include <unistd.h>
#include <limits.h>


// Virtual button codes that are not defined by X11.
// Btn1 -> left
// Btn3 -> right
#define Button1			1
#define Button2			2
#define Button3			3
#define WheelUp			4
#define WheelDown		5
#define WheelLeft		6
#define WheelRight		7
#define XButton1		8
#define XButton2		9

DeepinMonitor::DeepinMonitor(QObject *parent) : IMonitor(parent)
{
    if (!QDBusConnection::sessionBus().isConnected())
    {
        qWarning() << "Cannot connect to dbus";
        return;
    }
    QStringList req;
    req << "org.ayatana.bamf" << "com.deepin.api.XEventMonitor" << "org.kde.KWin";
    QDBusConnectionInterface *interface = QDBusConnection::sessionBus().interface();
    QStringList services = interface->registeredServiceNames().value();
    for (auto &s : req)
    {
        if (!services.contains(s))
            qWarning() << "Cannot find dbus service " + s;
    }
    connectSignals();
    m_keyMap = Platform::getKeyMap();

    QDBusMessage msg = QDBusMessage::createMethodCall("com.deepin.api.XEventMonitor",
                                                      "/com/deepin/api/XEventMonitor",
                                                      "com.deepin.api.XEventMonitor",
                                                      "RegisterFullScreen");

    auto reply = QDBusConnection::sessionBus().call(msg);
    if (reply.type() == QDBusMessage::ReplyMessage)
        gid = reply.arguments()[0].toString();

}

void DeepinMonitor::connectSignals()
{
    QDBusConnection::sessionBus().connect("com.deepin.api.XEventMonitor",
                                          "/com/deepin/api/XEventMonitor",
                                          "com.deepin.api.XEventMonitor",
                                          "ButtonPress",
                                          this, SLOT(onButtonPressed(int,int,int,QString)));

    QDBusConnection::sessionBus().connect("com.deepin.api.XEventMonitor",
                                          "/com/deepin/api/XEventMonitor",
                                          "com.deepin.api.XEventMonitor",
                                          "ButtonRelease",
                                          this, SLOT(onButtonReleased(int,int,int,QString)));

    QDBusConnection::sessionBus().connect("com.deepin.api.XEventMonitor",
                                          "/com/deepin/api/XEventMonitor",
                                          "com.deepin.api.XEventMonitor",
                                          "KeyPress",
                                          this, SLOT(onKeyPressed(QString,int,int,QString)));

    QDBusConnection::sessionBus().connect("com.deepin.api.XEventMonitor",
                                          "/com/deepin/api/XEventMonitor",
                                          "com.deepin.api.XEventMonitor",
                                          "KeyRelease",
                                          this, SLOT(onKeyReleased(QString,int,int,QString)));

    QDBusConnection::sessionBus().connect("com.deepin.Screenshot",
                                          "/com/deepin/Screenshot",
                                          "com.deepin.Screenshot",
                                          "Done",
                                          this, SIGNAL(screenShotDone(QString)));

    Picker::instance();
    connect(this, &DeepinMonitor::mouseLeftBtnPressed, &Picker::instance(), &Picker::onButtonPressed);
    connect(this, &DeepinMonitor::mouseLeftBtnReleased, &Picker::instance(), &Picker::onButtonReleased);
    connect(&Picker::instance(), &Picker::wordsPicked, this, &DeepinMonitor::contentPicked);
}


void DeepinMonitor::onButtonPressed(int button, int x, int y, QString id)
{
     //qInfo() << id;
    if (id != gid)
        return;
    QPoint p(x, y);
    emit mouseBtnPressed(p);
    if (button == Button1)
        emit mouseLeftBtnPressed(p);
    else if (button == Button3)
        emit mouseRightBtnPressed(p);
    else if (button == WheelUp || button == WheelDown)
        emit mouseWheel(p);
}

void DeepinMonitor::onButtonReleased(int button, int x, int y, QString id)
{
    //qInfo() << id;
    if (id != gid)
        return;
    QPoint p(x, y);
    emit mouseBtnReleased(p);
    if (button == Button1)
        emit mouseLeftBtnReleased(p);
    else if (button == Button3)
        emit mouseRightBtnReleased(p);
}

void DeepinMonitor::onKeyPressed(QString name, int x, int y, QString)
{
    Q_UNUSED(x)
    Q_UNUSED(y)

    emit keyPressed(name);
    if (m_keyMap.contains(name))
        emit keyPressed(m_keyMap[name]);

}

void DeepinMonitor::onKeyReleased(QString name, int x, int y, QString)
{
    Q_UNUSED(x)
    Q_UNUSED(y)

    emit keyReleased(name);
    if (m_keyMap.contains(name))
        emit keyReleased(m_keyMap[name]);

}


DeepinMonitor& DeepinMonitor::instance()
{
    static DeepinMonitor m;
    return m;
}

void DeepinMonitor::screenShot()
{
    QDBusMessage msg = QDBusMessage::createMethodCall("com.deepin.Screenshot",
                                                      "/com/deepin/Screenshot",
                                                      "com.deepin.Screenshot",
                                                      "StartScreenshotFor3rd");

    msg.setArguments(QList<QVariant> {"/tmp"});
    QDBusConnection::sessionBus().call(msg);
}

void DeepinMonitor::stopMonitor()
{
    QDBusConnection::sessionBus().disconnect("com.deepin.api.XEventMonitor",
                                          "/com/deepin/api/XEventMonitor",
                                          "com.deepin.api.XEventMonitor",
                                          "ButtonPress",
                                          this, SLOT(onButtonPressed(int,int,int,QString)));

    QDBusConnection::sessionBus().disconnect("com.deepin.api.XEventMonitor",
                                          "/com/deepin/api/XEventMonitor",
                                          "com.deepin.api.XEventMonitor",
                                          "ButtonRelease",
                                          this, SLOT(onButtonReleased(int,int,int,QString)));

    QDBusConnection::sessionBus().disconnect("com.deepin.api.XEventMonitor",
                                          "/com/deepin/api/XEventMonitor",
                                          "com.deepin.api.XEventMonitor",
                                          "KeyPress",
                                          this, SLOT(onKeyPressed(QString,int,int,QString)));

    QDBusConnection::sessionBus().disconnect("com.deepin.api.XEventMonitor",
                                          "/com/deepin/api/XEventMonitor",
                                          "com.deepin.api.XEventMonitor",
                                          "KeyRelease",
                                          this, SLOT(onKeyReleased(QString,int,int,QString)));

    QDBusConnection::sessionBus().disconnect("com.deepin.Screenshot",
                                          "/com/deepin/Screenshot",
                                          "com.deepin.Screenshot",
                                          "Done",
                                          this, SIGNAL(screenShotDone(QString)));
}

